/*
 * Hyuga: A Density-Grid Stream Clustering Platform.
 * Copyright (C) 2014 PUC-Rio/Laboratory for Advanced Collaboration
 *
 * Hyuga is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Hyuga is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Hyuga. If not, see <http://www.gnu.org/licenses/>.
 */
package br.pucrio.inf.lac.konoha.hyuga.core;

import java.util.Scanner;

import org.apache.log4j.Logger;

import br.pucrio.inf.lac.konoha.hyuga.command.Command;
import br.pucrio.inf.lac.konoha.hyuga.command.CommandFactory;
import lac.cnet.sddl.objects.ApplicationObject;
import lac.cnet.sddl.objects.MetaMessage;
import lac.cnet.sddl.udi.core.listener.UDIDataReaderListener;

/**
 * A shell to interact with the Hyuga service based on the Command pattern. It can handle local and remote commands. 
 * 
 * @author Marcos Roriz <mroriz@inf.puc-rio.br>
 */
public class Shell implements UDIDataReaderListener<ApplicationObject> {
    
    /** Command Factory. */
    private CommandFactory cm;
    
    /** LOGGER. */
    private static Logger LOGGER = Logger.getLogger(Shell.class.getCanonicalName());
    
    /**
     * Creates a shell using a given command factory.
     * 
     * @param cm the command factory.
     */
    public Shell(CommandFactory cm) {
        this.cm = cm;
    }
    
    /**
     * Shell info (for console output)
     * 
     * @param scenario the monitored domain and variables.
     * @param debug if debug is enabled;
     */
    public void printShellInfo(Scenario scenario, boolean debug) {
        StringBuffer sb = new StringBuffer();
        sb.append("         __  __                                  ").append("\n");                       
        sb.append("        / / / /_  ____  ______ _____ _           ").append("\n");
        sb.append("       / /_/ / / / / / / / __ `/ __ `/           ").append("\n");
        sb.append("      / __  / /_/ / /_/ / /_/ / /_/ /            ").append("\n");
        sb.append("     /_/ /_/\\__, /\\__,_/\\__, /\\__,_/         ").append("\n");
        sb.append("           /____/      /____/                    ").append("\n");
        sb.append("\n");
        sb.append(scenario.toString());
        sb.append("\n\tDEBUG MODE: " + debug).append("\n");
        sb.append(cm.toString());
        
        System.out.println(sb);
    }
    
    // Local Commands
    public void loop() {
        Scanner scan = new Scanner(System.in);
        System.out.print("$ ");
        
        while (scan.hasNext()) {
            executeCommand(scan.nextLine());
            System.out.print("$ ");
        }

        scan.close();
    }
    
    // Remote Commands
    @Override
    public void onNewData(ApplicationObject dataStreamMsg) {
        MetaMessage metaMessage = (MetaMessage) dataStreamMsg;
        executeCommand(metaMessage.getCommand());
    }
    
    /**
     * Execute a given command (either remote or local).
     * 
     * @param commandSTR the command string.
     */
    private synchronized void executeCommand(String commandSTR) {
        Command command = cm.getCommand(commandSTR);
        try {
            command.execute();
        } catch (Exception ex) {
            LOGGER.error("ERROR AT executting command" + command.getCommandSTR());
        }
    }
}
